﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using TE3.Entities;
using TE3.Utils;
using System.IO;
namespace TE3
{
	public delegate void ConsoleCommand(string[] parameters);
	public class ConsoleCommands
	{
		private readonly Dictionary<string, ConsoleCommand> _consoleCommands;
		private readonly Dictionary<string, string> _consoleCommandsHelp;
		private readonly TE3Game _currentGame;
		public string[] LastCommand;
		public Window ConsoleWindow;
		public ConsoleCommands(TE3Game currentGame)
		{
			_currentGame = currentGame;
			_consoleCommands = new Dictionary<string, ConsoleCommand>();
			_consoleCommandsHelp = new Dictionary<string, string>();
			AddCommand("echo", parameters => Console.WriteLine(parameters[1]),"Prints text into console.");
			AddCommand("add_box",parameters =>
			{
				var box = new Box
				{
					Position = _currentGame.EntityManager.Entities["MouseCursor"].Position
				};
				_currentGame.EntityManager.AddEntity(box, _currentGame.EntityManager.Entities.Count.ToString(),true,true);
			}, "Creates a new Box at the position of mouse cursor.");
			AddCommand("entlist", parameters =>
			{
				Console.WriteLine("entlist\n{");
				foreach (var entity in _currentGame.EntityManager.Entities.Keys)
				{
					var ent = _currentGame.EntityManager.Entities[entity];
					Console.WriteLine("["+entity+"][" + ent.GetType() + "] at " + ent.Position.ToString());
				}
				Console.WriteLine("}");
			}, "Prints complete list of all entities in map.");
			AddCommand("window", parameters =>
			{
				if(!_currentGame.WindowManager.Windows.ContainsKey(parameters[1]))
				{
					Console.WriteLine("Window \"" + parameters[1] + "\" doesn't exist!");
					return;
				}
				var w = _currentGame.WindowManager.Windows[parameters[1]];
				switch (parameters[2])
				{
					case "show":
						w.Show();
						break;
					case "hide":
						w.Hide();
						break;
					case "toggle":
						w.Toggle();
						break;
				}
			},
			"\n\tshow - Makes window with the given name visible\n" +
			"\thide - Hides window with the given name\n" +
			"\ttoggle - Toggles visibility of window with the given name"
			);
			AddCommand("windowlist", parameters =>
			{
				Console.WriteLine("windowlist\n{");
				foreach (var windowName in _currentGame.WindowManager.Windows.Keys)
				{
					Console.WriteLine("[" + windowName + "], Hidden = " + _currentGame.WindowManager.Windows[windowName].Hidden);
				}
				Console.WriteLine("}");
			}, "Prints complete list of all windows");
			AddCommand("drawableslist", parameters =>
			{
				Console.WriteLine("drawableslist\n{");
				foreach (var drawable in _currentGame.DrawManager.Drawables)
				{
					Console.WriteLine("["+drawable.Key+"]");		
				}
				Console.WriteLine("}");
			}, "Prints complete list of all drawables");
			AddCommand("clearents", parameters =>
			{
				var keyList = _currentGame.EntityManager.Entities.Select(entity => entity.Key).ToList();
				foreach (var key in keyList.Where(key => key != "MouseCursor"))
				{
					_currentGame.EntityManager.DestroyEntity(key);
				}
			});
			AddCommand("fml", parameters =>
			{
				var rand = new Random();
				for(var i = 0; i < Convert.ToInt32(parameters[1]); i++)
				{
					var pos = Int2.GetRandom(rand, 0, _currentGame.GraphicsDevice.Viewport.Width, 0, _currentGame.GraphicsDevice.Viewport.Height);
					var newBox = new Box {Position = pos};
					_currentGame.EntityManager.AddEntity(newBox, _currentGame.EntityManager.Entities.Count.ToString(),true,true);
				}
			});
			AddCommand("entcount", parameters => Console.WriteLine("entcount = " + _currentGame.EntityManager.Entities.Count));
			AddCommand("compilefile", parameters =>
			{
				var reader = new StreamReader(Environment.CurrentDirectory + "\\Scripts\\" + parameters[1]);
				var fileName = Script.Compile(reader.ReadToEnd(),Path.GetFileName(parameters[1]));
				Console.WriteLine("Executing...");
				Script.Execute(fileName,_currentGame);
			});
			AddCommand("help", parameters =>
			{
				if(parameters[1] == "*")
				{
					foreach (var consoleCommand in _consoleCommands)
					{
						Console.Write(consoleCommand.Key + " - ");
						Console.WriteLine(_consoleCommandsHelp[consoleCommand.Key] ?? "Description not available");
					}
				}
				if(_consoleCommands.ContainsKey(parameters[1]))
				{
					Console.Write(parameters[1] + " - ");
					Console.WriteLine(_consoleCommandsHelp[parameters[1]] ?? "Description is not available for this command");
				}
				else
				{
					Console.WriteLine("Command \"" + parameters[1] + "\" doesn't exist. Type \"help *\" for a listing of all commands");
				}
			}, "WE HAVE TO GO DEEPER");
			AddCommand("cls", parameters => Console.Clear());
			ConsoleWindow = new Window("Console",new Rectangle(0,0,_currentGame.Window.ClientBounds.Width,_currentGame.Window.ClientBounds.Height - 400),_currentGame, new Color(255,255,255,128))
			                	{Hidden = true};
		}
		public bool CommandExists(string command)
		{
			return _consoleCommands.ContainsKey(command);
		}
		public bool RunCommand(string command, string[] parameters = null)
		{
			if(!CommandExists(command)) return false;
			try
			{
				_consoleCommands[command].Invoke(parameters);
			}
			catch(IndexOutOfRangeException)
			{
				Console.WriteLine("Not enough parameters!");
			}
			catch (Exception e)
			{
				Console.WriteLine("Generic error!");
				Console.WriteLine(e.Message);
			}
			LastCommand = parameters;
			return true;
		}
		public void AddCommand(string commandName, ConsoleCommand command, string description = null)
		{
			_consoleCommands.Add(commandName,command);
			_consoleCommandsHelp.Add(commandName, description);
		}
		public void RunLastCommand()
		{
			if(LastCommand != null)
				RunCommand(LastCommand[0], LastCommand);
		}
	}
}
